import json
import os
import subprocess
import tkinter as tk
import paho.mqtt.client as mqtt

from Ini_utils import UtilIni
from common_util import CommonUtil
from true_util_payload import UtilText, get_payload, replace_load
from utils.common_util import get_current_time, extract_value_from_json_file, get_current_date
from utils.logging_util import Log
from utils.path_util import conf_path, logging_path


class MqttClient:
    def __init__(self, mqtt_address, username, password, topic):
        self.port = int(UtilIni().getvalue('AutoStation', 'port'))
        self.spotCode = UtilIni().getvalue('AutoStation', 'spotCode')
        self.station_no = UtilIni().getvalue('AutoStation', 'stationno')
        self.product_code = UtilIni().getvalue('AutoStation', 'productCode')
        self.spot_product_code = UtilIni().getvalue('AutoStation', 'spotProductCode')
        self.mqtt_address = mqtt_address
        self.username = username
        self.password = password
        self.topic = topic
        self.client = mqtt.Client()
        self.client.username_pw_set(username, password)
        self.client.connect(mqtt_address, self.port, 60)
        self.client.on_message = self.on_message
        self.client.subscribe(f'{self.product_code}/{self.station_no}/M2S/request')
        self.client.subscribe(f'{self.spot_product_code}/{self.spotCode}/M2S/request')
        self.client.loop_start()

    def on_connect(self, client, userdata, flags, rc):
        if rc == 0:
            self.connect_status = True
            app.received_message_text.insert(1.0, "Connection is connecting....\n")
        else:
            app.received_message_text.insert(1.0, "Connection is refused....\n")

    def on_message(self, client, userdata, msg):
        message = msg.payload.decode('utf-8')
        topic = msg.topic
        Log().debug(f"Received message is topic:{topic},payload:{message}\n")
        receive_payload = json.loads(message)
        Log().debug(f"Received message is topic:{topic},payload:{receive_payload}\n")
        app.update_received_message(f'Receive topic is：{topic}\n')
        app.update_received_message(f'Receive payload is：{message}\n')
        if app.listen_var.get():
            response_payload = extract_value_from_json_file("template.json")
            UtilText(receive_text=receive_payload, response_text=response_payload,
                     topic=topic).util_response()

    def send_message(self, topic, payload):
        return self.client.publish(topic, payload)


class App:
    def __init__(self, root):
        self.root = root
        self.root.title("AutoStation")
        self.stationNo = UtilIni().getvalue('AutoStation', 'stationNo')
        self.product_code = UtilIni().getvalue('AutoStation', 'productcode')
        self.spotCode = UtilIni().getvalue('AutoStation', 'spotcode')
        self.spotProductCode = UtilIni().getvalue('AutoStation', 'spotproductcode')
        screen_width = root.winfo_screenwidth()
        screen_height = root.winfo_screenheight()
        new_width = int(screen_width * 3 / 4)
        new_height = int(screen_height * 3 / 4)
        x_offset = (screen_width - new_width) // 2
        y_offset = (screen_height - new_height) // 2
        root.geometry(f"{new_width}x{new_height}+{x_offset}+{y_offset}")

        ip_var = tk.StringVar(value=UtilIni().getvalue('AutoStation', 'ip'))
        self.label_mqtt_address = tk.Label(root, text="MQTT地址:")
        self.entry_mqtt_address = tk.Entry(root, state='readonly', textvariable=ip_var)
        self.label_mqtt_address.pack()
        self.entry_mqtt_address.pack()

        name_var = tk.StringVar(value=UtilIni().getvalue('AutoStation', 'name'))
        self.label_username = tk.Label(root, text="用户名:")
        self.entry_username = tk.Entry(root, state='readonly', textvariable=name_var)
        self.label_username.pack()
        self.entry_username.pack()
        pwd_var = tk.StringVar(value=UtilIni().getvalue('AutoStation', 'pwd'))
        self.label_password = tk.Label(root, text="密码:")
        self.label_password.pack()
        self.entry_password = tk.Entry(root, show="*", state='readonly', textvariable=pwd_var)
        self.entry_password.pack()

        self.label_topic = tk.Label(root, text="换电站编码:")
        self.label_topic.pack()
        stationNo_var = tk.StringVar(value=UtilIni().getvalue('AutoStation', 'stationNo'))
        self.entry_topic = tk.Entry(root, state='readonly', textvariable=stationNo_var)
        self.entry_topic.pack()

        self.charging_station_button = tk.Button(root, text="充电桩充电", fg="green", command=self.on_spotRecord)
        self.charging_station_button.place(x=300, y=100)

        self.station_control_button = tk.Button(root, text="站控 换电", fg='red', command=self.on_swapRecord)
        self.station_control_button.place(x=300, y=150)

        self.charging_gun_button = tk.Button(root, text="充电枪充电", fg='blue', command=self.on_chargingGunRecord)
        self.charging_gun_button.place(x=300, y=200)

        # self.charging_gun_button = tk.Button(root, text="插枪实时数据", fg='blue', command=self.on_chargingData)
        # self.charging_gun_button.place(x=750, y=100)
        #
        # self.charging_gun_button = tk.Button(root, text="充电桩实时数据", fg='blue', command=self.on_chargeState)
        # self.charging_gun_button.place(x=750, y=150)

        self.label_spot = tk.Label(root, text="充电桩编码:")
        self.label_spot.pack()
        stationNo_var = tk.StringVar(value=UtilIni().getvalue('AutoStation', 'spotCode'))
        self.entry_spot = tk.Entry(root, state='readonly', textvariable=stationNo_var)
        self.entry_spot.pack()
        self.connect_button = tk.Button(root, text="连接", fg="blue", command=self.connect_mqtt)
        self.connect_button.pack()
        self.clear_button = tk.Button(self.root, text="清除", fg="green", command=self.clear_received_message)
        self.clear_button.pack()
        self.disconnect_button = tk.Button(root, text="断开", fg='red', command=self.disconnect_mqtt)
        self.disconnect_button.pack()
        self.open_log_button = tk.Button(root, text="打开日志", fg='orange', command=self.open_log_file)
        self.open_log_button.place(x=650, y=200)
        self.listen_var = tk.BooleanVar(value=True)
        checkbutton = tk.Checkbutton(root, text="是否自动回复", variable=self.listen_var)
        checkbutton.pack()
        self.connect_button.config(state=tk.NORMAL)  # 初始化时点亮连接按钮
        self.label_received_message = tk.Label(root, text="接收到的消息:")
        self.label_received_message.pack()
        self.message_frame = tk.Frame(root)
        self.message_frame.pack(fill=tk.BOTH, expand=True)

        self.received_message_text = tk.Text(self.message_frame, height=7, width=50)
        self.received_message_text.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)

        self.scrollbar = tk.Scrollbar(self.message_frame, command=self.received_message_text.yview)
        self.scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        self.received_message_text.config(yscrollcommand=self.scrollbar.set)
        self.label_reply_topic = tk.Label(root, text="回复消息的主题:")
        self.label_reply_topic.pack()
        self.entry_reply_topic = tk.Entry(root, width=40)
        self.entry_reply_topic.pack()
        self.label_reply_payload = tk.Label(root, text="回复消息的内容:")
        self.label_reply_payload.pack()
        self.entry_reply_payload = tk.Entry(root)
        self.entry_reply_payload.pack(fill=tk.BOTH, expand=True)
        self.entry_reply_text = tk.Text(self.entry_reply_payload, height=3, width=40)
        self.entry_reply_text.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)

        self.reply_button = tk.Button(root, text="回复", command=self.send_reply)
        self.reply_button.pack()
        self.test_json = os.path.join(conf_path, "template.json")
        self.timers = []
        self.mqtt_client = None

    def connect_mqtt(self):
        try:
            mqtt_address = self.entry_mqtt_address.get()
            username = self.entry_username.get()
            password = self.entry_password.get()
            topic = self.entry_topic.get()
            self.mqtt_client = MqttClient(mqtt_address, username, password, topic)
            self.clear_received_message()
            app.received_message_text.insert(1.0, "Connection is connected...." + "\n")
            self.connect_button.config(state=tk.DISABLED)
            self.disconnect_button.config(state=tk.NORMAL)
            self.start_timed_task6()
            self.start_timed_task1()
            self.start_timed_task2()
            self.start_timed_task3()
            self.start_timed_task4()
            self.start_timed_task5()

        except Exception as e:
            app.received_message_text.insert(1.0, 'Connection is refused....' + "\n")
            app.received_message_text.insert(1.0, e + "\n")

    def open_log_file(self):
        log_filename = os.path.join(logging_path, get_current_date() + '.txt')

        if os.path.exists(log_filename):
            subprocess.Popen(["notepad", log_filename], shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
                             stdin=subprocess.PIPE, creationflags=0x08000000)
        else:
            Log().debug('Log file is not exist....')

    # 充电桩充电按钮事件
    def on_spotRecord(self):
        if self.mqtt_client:
            payload = extract_value_from_json_file(self.test_json)
            payload = get_payload(payload=payload, function="spotChargeRecord")
            payload = replace_load(payload)
            payload['dataBody']['orderSn'] = CommonUtil.make_chg_sn()
            payload['dataBody']['chgCode'] = CommonUtil.get_spotCode()
            self.mqtt_client.send_message(topic=f"{self.spotProductCode}/{self.spotCode}/S2M/event",
                                          payload=json.dumps(payload))
            self.update_received_message(f'spotChargeRecord is sending....')
            Log().debug(f'spotRecord is sending,spotCode:{self.spotCode},payload:{json.dumps(payload)}')

    # 插枪实时数据
    def on_chargingData(self):
        if self.mqtt_client:
            payload = extract_value_from_json_file(self.test_json)
            payload = get_payload(payload=payload, function="chargingData")
            payload['dataBody']['chgList'][0]['soc'] = CommonUtil.get_soc()
            payload = replace_load(payload)
            self.mqtt_client.send_message(topic=f"{self.product_code}/{self.stationNo}/S2M/state",
                                          payload=json.dumps(payload))
            self.update_received_message(f'chargingData is sending....')
            Log().debug(f'chargingData is sending,station:{self.stationNo},payload:{json.dumps(payload)}')

    # 充电桩实时数据
    def on_chargeState(self):
        if self.mqtt_client:
            payload = extract_value_from_json_file(self.test_json)
            payload = get_payload(payload=payload, function="chargeState")
            payload['dataBody']['soc'] = CommonUtil.get_soc()
            payload = replace_load(payload)
            self.mqtt_client.send_message(topic=f"{self.product_code}/{self.spotCode}/S2M/state",
                                          payload=json.dumps(payload))
            self.update_received_message(f'chargeState is sending....')
            Log().debug(f'chargeState is sending,spotCode:{self.spotCode},payload:{json.dumps(payload)}')


    def on_chargingGunRecord(self):
        if self.mqtt_client:
            payload = extract_value_from_json_file(self.test_json)
            payload = get_payload(payload=payload, function="chargeRecord")
            payload = replace_load(payload)
            payload['dataBody']['chgSwitch'] = 1
            payload['dataBody']['startType'] = 3
            payload['dataBody']['orderSn'] = CommonUtil.make_chg_sn()
            self.mqtt_client.send_message(topic=f"{self.product_code}/{self.stationNo}/S2M/event",
                                          payload=json.dumps(payload))
            self.update_received_message(f'chargingGunRecord is sending....')
            Log().debug(
                f'chargingGunRecord is sending,topic:f"{self.spotProductCode}/{self.spotCode}/S2M/event",payload:{json.dumps(payload)}')

    # 站控换电

    def on_swapRecord(self):
        if self.mqtt_client:
            payload = extract_value_from_json_file(self.test_json)
            payload = get_payload(payload=payload, function="swapRecord")
            payload = replace_load(payload)
            payload['dataBody']['swapStartType'] = 1
            payload['dataBody']['orderSn'] = CommonUtil.make_chg_sn()
            self.mqtt_client.send_message(topic=f"{self.product_code}/{self.stationNo}/S2M/event",
                                          payload=json.dumps(payload))
            self.update_received_message(f'swapRecord is sending....')
            Log().debug(f'swapRecord is sending,station:{self.stationNo},payload:{json.dumps(payload)}')

    def disconnect_mqtt(self):
        if self.mqtt_client:
            self.mqtt_client.client.disconnect()
            self.clear_received_message()
            self.received_message_text.insert(1.0, "Connection Disconnected...." + '\n')
            self.connect_button.config(state=tk.NORMAL)
            self.disconnect_button.config(state=tk.DISABLED)
            for timer in self.timers:
                self.root.after_cancel(timer)  # Cancel all timers
            self.timers = []  # Clear the timers list

    def clear_received_message(self):
        self.received_message_text.delete(1.0, tk.END)

    def update_received_message(self, message):
        self.received_message_text.insert(tk.END, message + "\n")

    def send_reply(self):
        if self.mqtt_client:
            reply_topic = self.entry_reply_topic.get()
            reply_payload = self.entry_reply_payload.get()
            if reply_topic and reply_payload:
                self.mqtt_client.send_message(reply_topic, json.dumps(reply_payload))
                Log.info(f'Reply message is {reply_topic, json.dumps(reply_payload)}')

    def start_timed_task1(self):
        self.do_timed_task1()  # 执行定时任务
        timer1 = self.root.after(1000 * 30, self.start_timed_task1)
        self.timers.append(timer1)  # 每30秒调度执行一次定时任务

    def start_timed_task2(self):
        self.do_timed_task2()  # 执行定时任务
        timer2 = self.root.after(1000 * 60 * 5, self.start_timed_task2)
        self.timers.append(timer2)  # 每10min调度执行一次定时任务

    def start_timed_task3(self):
        self.do_timed_task3()  # 执行定时任务
        timer2 = self.root.after(1000 * 60 * 5, self.start_timed_task3)
        self.timers.append(timer2)  # 每10min调度执行一次定时任务

    def start_timed_task4(self):
        self.do_timed_task4()  # 执行定时任务
        timer2 = self.root.after(1000 * 60 * 10, self.start_timed_task4)
        self.timers.append(timer2)  # 每10min调度执行一次定时任务

    def start_timed_task5(self):
        self.do_timed_task5()  # 执行定时任务
        timer2 = self.root.after(1000 * 60 * 10, self.start_timed_task5)
        self.timers.append(timer2)  # 每10min调度执行一次定时任务

    def start_timed_task6(self):
        self.do_timed_task6()  # 执行定时任务
        timer2 = self.root.after(1000 * 60 * 60, self.start_timed_task6)
        self.timers.append(timer2)  # 每10min调度执行一次定时任务

    def do_timed_task1(self):
        if self.mqtt_client:
            self.mqtt_client.send_message(topic=f"{self.product_code}/{self.stationNo}/S2M/keepalive",
                                          payload=get_current_time())
            self.update_received_message(f'HeartBeat is sending...')
            Log().debug(f'HeartBeat is sending:{get_current_time()}')

    def do_timed_task2(self):
        if self.mqtt_client:
            payload = extract_value_from_json_file(self.test_json)
            payload = get_payload(payload=payload, function="cabinetState")
            payload = replace_load(payload)
            self.mqtt_client.send_message(topic=f"{self.product_code}/{self.stationNo}/S2M/state",
                                          payload=json.dumps(payload))
            Log().debug(f'CabinetState is sending,station:{self.stationNo},payload:{json.dumps(payload)}')
            self.update_received_message(f'CabinetState is sending....')

    def do_timed_task3(self):
        if self.mqtt_client:
            payload = extract_value_from_json_file(self.test_json)
            payload = get_payload(payload=payload, function="chargerState")
            payload = replace_load(payload)
            self.mqtt_client.send_message(topic=f"{self.product_code}/{self.stationNo}/S2M/state",
                                          payload=json.dumps(payload))
            self.update_received_message(f'ChargerState is sending....')
            Log().debug(f'ChargerState is sending,station:{self.stationNo},payload:{json.dumps(payload)}')

    def do_timed_task4(self):
        if self.mqtt_client:
            payload = extract_value_from_json_file(self.test_json)
            payload = get_payload(payload=payload, function="stationState")
            payload = replace_load(payload)
            self.mqtt_client.send_message(topic=f"{self.product_code}/{self.stationNo}/S2M/state",
                                          payload=json.dumps(payload))
            self.update_received_message(f'StationState is sending....')
            Log().debug(f'StationState is sending,station:{self.stationNo},payload:{json.dumps(payload)}')

    def do_timed_task5(self):
        if self.mqtt_client:
            payload = extract_value_from_json_file(self.test_json)
            payload = get_payload(payload=payload, function="batState")
            payload = replace_load(payload)
            self.mqtt_client.send_message(topic=f"{self.product_code}/{self.stationNo}/S2M/state",
                                          payload=json.dumps(payload))
            self.update_received_message(f'BatState is sending....')
            Log().debug(f'BatState is sending,station:{self.stationNo},payload:{json.dumps(payload)}')

    def do_timed_task6(self):
        if self.mqtt_client:
            payload = extract_value_from_json_file(self.test_json)
            payload = get_payload(payload=payload, function="stationInfo")
            payload = replace_load(payload)
            self.mqtt_client.send_message(topic=f"{self.product_code}/{self.stationNo}/S2M/state",
                                          payload=json.dumps(payload))
            self.update_received_message(f'stationInfo is sending....')
            Log().debug(f'stationInfo is sending,station:{self.stationNo},payload:{json.dumps(payload)}')


if __name__ == "__main__":
    root = tk.Tk()
    app = App(root)
    root.mainloop()
